import * as fs from "fs"
import * as cp from "child_process"

let getShaMap = new Map<string, Promise<string | undefined>>();
async function getSha32(depDir: string) {
    let task = getShaMap.get(depDir)
    if (task == null) {
        task = _getSha(depDir)
        getShaMap.set(depDir, task)
    }
    return task;
}

async function _getSha(depDir: string) {
    console.log(`update sha32: ${depDir}`)
    try {
        console.log(`pull repo: ${depDir}`)
        await cp.exec(`cd /d ${depDir} && git remote update`, (err, stdout) => { })
        let isDiff = true
        await new Promise<void>((resolve, reject) => {
            var p = cp.exec(`cd /d ${depDir} && git status`, (err, stdout, stderr) => {
                // console.log(stdout, stderr)
                if (stdout.indexOf(" is up to date with ") >= 0) {
                    isDiff = false;
                }
                resolve()
            });
        })
        if (isDiff) {
            let cp2 = await cp.exec(`cd /d ${depDir} && git pull && git push`, (err, stdout) => {
                if (err) {
                    console.error(`pull failed: ${depDir}`)
                    console.error(err)
                }
                if (stdout) {
                    console.log(stdout)
                }
            })
        }
        let urlsStr = cp.execSync(`cd /d ${depDir} && git remote -v`).toString();
        let urls = urlsStr.split("\n").map(url => {
            let lines = url.split(/\s/)
            return lines[1];
        })
        let url = urls[0]
        let giteeUrl = url.replace(`://github.`, `://gitee.`)
        await cp.exec(`cd /d ${depDir} && git push ${giteeUrl}`, (err, stdout) => {
            if (err) {
                console.error(`pull failed: ${depDir}`)
                console.error(err)
            }
            if (stdout) {
                console.log(stdout)
            }
        })
        let sha32 = cp.execSync(`cd /d ${depDir} && git rev-parse HEAD`).toString().trim()
        console.log(`sha32: ${depDir} -> ${sha32}`)
        return sha32
    } catch (err) {
        console.error(`update-failed: ${depDir}`)
        console.error(err)
    }
}

export async function UpdateManifest(argv: string[]) {
    let libdir = argv[argv.indexOf("--libdir") + 1]
    let manifestPath = argv[argv.indexOf("--manifest") + 1]

    if (libdir == null || libdir == "" || !fs.existsSync(libdir)) {
        console.error(`无效libdir路径: ${libdir}`)
        return
    }
    if (manifestPath == null || manifestPath == "" || !fs.existsSync(manifestPath)) {
        console.error(`无效manifestPath: ${manifestPath}`)
        return
    }

    let manifestContent = fs.readFileSync(manifestPath, "utf-8")
    let manifest = JSON.parse(manifestContent)
    let deps: { [key: string]: string } = manifest["dependencies"]
    let keys = Object.keys(deps).filter(key => {
        let v = deps[key]
        return v.indexOf("/windyuuy/") >= 0
    })
    let pathRegex = /(.+?\/windyuuy\/([\w\-\.]+).git(?:\?path\=([\w\/\.\@]+))?)(?:\#(\w+))?/
    let urls = await Promise.all(keys.map(async (key) => {
        let url = deps[key]
        let m = url.match(pathRegex)!
        if (m != null) {
            let l1 = m[1]
            let p1 = m[2]
            let p2 = m[3]
            let sha = m[4]
            if (sha != null) {
                let subDir = p2 != null ? `${p1}/${p2}` : p1
                let depDir = `${libdir}/${p1}`
                let libDir = `${libdir}/${subDir}`
                if (fs.existsSync(libDir) && fs.existsSync(`${depDir}/.git`)) {
                    console.log(`begin: ${libDir}, ${depDir}`)
                    let sha32 = await getSha32(depDir)
                    let line = `${l1}#${sha32}`
                    return line
                }
            }
        } else {
            console.log(`无法解析的Url: ${url}`)
        }
        return null
    }))

    for (let i = 0; i < keys.length; i++) {
        let key = keys[i]
        let url = urls[i]
        if (url != null) {
            deps[key] = url
        }
    }

    let manifestContent2 = JSON.stringify(manifest, null, 2)
    if (manifestContent != manifestContent2) {
        fs.writeFileSync(manifestPath, manifestContent2, "utf-8")
    }
}
